package battleship.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

import battleship.Setup;
import battleship.boat.Boat;
import battleship.field.Field;
import battleship.player.Player;

@SuppressWarnings("serial")
public class FieldPainter extends JPanel {
	
	private Point lastPointHighlighted = new Point(0,0);
	private Point lastPointClicked = null;
	private JLabel notificationArea;
	
	private boolean hideShips = false;
	
	private Player fieldOwner;
	
	private boolean vertical = true;
	
	private Image[] images;
	private Image[] imagesv;
	
	private Image hit;
	private Image miss;
	
	private boolean enabled = true;
	
	private long lastNotificationTime;
	private long lastNotificationFadeTime = 2000;
	
	public FieldPainter(JLabel notificationArea)
	{
		this.notificationArea = notificationArea;
		setBackground(Color.BLUE);
		addListeners();
		
		loadImages();
		
		this.setPreferredSize(new Dimension(Field.getWidth() * 25, Field.getHeight() * 25));
	}
	
	public FieldPainter(Player owner, JLabel notificationArea)
	{
		this(notificationArea);
		this.fieldOwner = owner;
	}
	
	public void loadImages()
	{
		
		images = new Image[] {
				(new ImageIcon("images/mijnenveger.gif")).getImage(),
				(new ImageIcon("images/onderzeeer.gif")).getImage(),
				(new ImageIcon("images/kruiser.gif")).getImage(),
				(new ImageIcon("images/slagschip.gif")).getImage(),
				(new ImageIcon("images/vliegdekschip.gif")).getImage()
		};
		
		imagesv = new Image[] {
				(new ImageIcon("images/mijnenvegerv.gif")).getImage(),
				(new ImageIcon("images/onderzeeerv.gif")).getImage(),
				(new ImageIcon("images/kruiserv.gif")).getImage(),
				(new ImageIcon("images/slagschipv.gif")).getImage(),
				(new ImageIcon("images/vliegdekschipv.gif")).getImage()
		};
		
		hit = (new ImageIcon("images/fire.gif")).getImage();
		miss = (new ImageIcon("images/splash.gif")).getImage();
	}
	
	public void setEnabled(boolean enabled)
	{
		this.enabled = enabled;
	}
	
	public boolean getEnabled()
	{
		return enabled;
	}
	
	public void setNotificationText(String notification, boolean important)
	{
		if((lastNotificationTime + lastNotificationFadeTime) < System.currentTimeMillis() ||
				important)
		{
			this.getNotificationArea().setText(notification);
			if(important)
			{
				lastNotificationTime = System.currentTimeMillis();
			}
		}
	}
	
	public Player getFieldOwner()
	{
		return this.fieldOwner;
	}
	
	public void setFieldOwner(Player newOwner)
	{
		this.fieldOwner = newOwner;
	}
	
	public JLabel getNotificationArea()
	{
		return notificationArea;
	}
	
	@Override
	public void paintComponent(Graphics g)
	{
		Graphics2D g2 = (Graphics2D) g;
		GradientPaint gp = new GradientPaint(0.0f, 0.0f, new Color(40,200,180),
				   250.0f, 250.0f, new Color(40,100,210));
		g2.setPaint(gp);
		g2.fillRect(0, 0, Field.getWidth() * 25, Field.getHeight() * 25);
		
		g.setColor(Color.black);
		for (int i=1; i<Field.getWidth(); i++)
		{
			g2.drawLine(i*25,0,i*25,Field.getHeight() * 25);
		}
		for (int i=1; i<Field.getHeight(); i++)
		{
			g2.drawLine(0,i*25,Field.getWidth() * 25,i*25);
		}
		
		g2.draw3DRect(0,0,Field.getWidth() * 25,Field.getHeight() * 25,false);
		
		if(!hideShips)
		{
			drawBoats(g2);
		}
		
		if(Setup.getState() == Setup.LOOP)
		{
			drawHitMiss(g2);
		}
		
		setPreferredSize(new Dimension(Field.getWidth() * 25, Field.getHeight() * 25));
	}
	
	/**
	 * draws the boats onto the field
	 * 
	 * @param g2 Graphics2D object to paint with
	 */
	public void drawBoats(Graphics2D g2)
	{
		Boat boats[] = getFieldOwner().getField().getBoats();
		
		for (int boat = 0; boat < boats.length; boat++)
		{
			if(boats[boat] != null)
			{
				int x = boats[boat].getPositions()[0][1];
				int y = boats[boat].getPositions()[0][0];
				if(boats[boat].getVertical())
				{
					g2.drawImage(imagesv[boat], x * 25, y * 25, this);
				}
				else
				{
					g2.drawImage(images[boat], x * 25, y * 25, this);
				}
			}
		}
	}
	
	public void drawHitMiss(Graphics2D g2)
	{
		Field field = getFieldOwner().getField();
		
		for (int row = 0; row < Field.getHeight(); row++)
		{
			for(int column = 0; column < Field.getWidth(); column++)
			{
				boolean boatpresent = false;
				if(field.getField()[row][column])
				{
					for(int boat = 0; boat < field.getBoats().length; boat++)
					{
						if(field.getBoats()[boat].isHit(new int[] { row, column }) && !boatpresent)
						{
							g2.drawImage(hit, column * 25, row * 25, this);
							boatpresent = true;
						}
					}
					
					if(!boatpresent)
					{
						g2.drawImage(miss, column * 25, row * 25, this);
					}
				}
			}
		}	
	}
	
	public boolean getVertical()
	{
		return this.vertical;
	}
	
	public void resetLastPointClicked()
	{
		lastPointClicked = null;
	}
	
	public Point getLastPointClicked()
	{
		return this.lastPointClicked;
	}
	
	public Point getLastPointHighlighted()
	{
		return this.lastPointHighlighted;
	}
	
	public void addListeners()
	{
		this.addMouseMotionListener(new MouseMovementHandler());
		this.addMouseListener(new MouseHandler());
	}
	
	class MouseMovementHandler extends MouseMotionAdapter
	{

		public void mouseMoved(MouseEvent e) {
			int x = (int) (e.getPoint().getX()/25);
			int y = (int) (e.getPoint().getY()/25);

			Point highlighted = new Point(x, y);

			if (x < Field.getWidth() 
					&& y < Field.getHeight()
					&& !(highlighted.equals(lastPointHighlighted))
					&& getEnabled()) {

				lastPointHighlighted = highlighted;
				repaint();
			}
		}
	}
	
	private class MouseHandler extends MouseAdapter
	{
		public void mousePressed(MouseEvent e)
		{
			if(e.getModifiers() == InputEvent.BUTTON1_MASK && getEnabled())
			{
				lastPointClicked = new Point(e.getX()/25,e.getY()/25);
				repaint();
			}
			if(e.getModifiers() == InputEvent.BUTTON3_MASK && getEnabled())
			{
				vertical = !vertical;		//toggles vertical ship placing state
				repaint();
			}
		}
	}
	
	public void setHideShips(boolean hide)
	{
		this.hideShips = hide;
	}
	
	public boolean getHideShips()
	{
		return hideShips;
	}
}
